package study.translation.parser;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Lexer
{
    private static final Pattern SPACE = Pattern.compile( "(\\s*(\\/\\/.*)?)" );

    private BufferedReader reader;

    private String line;

    private int lineNum = 0;

    private int charNum = 0;

    private FilePosition begin;

    private FilePosition end;

    private boolean atEnd = false;

    public Lexer( InputStream inputStream )
    {
        reader = new BufferedReader( new InputStreamReader( inputStream ) );
        readSpace();
    }

    public Lexem readLexem( Lexem.Type type )
    {
        String contents = read( type.getPattern() );
        if( null != contents )
        {
            readSpace();
            return new Lexem( type, contents, begin, end );
        }
        return null;
    }

    public int getLineNumber()
    {
        return lineNum;
    }

    public int getCharNumber()
    {
        return charNum;
    }

    public String getCurrentLine()
    {
        return line;
    }

    public String getCodePart()
    {
        return ( null != line ) ? line.substring( charNum ) : "";
    }

    public boolean atEnd()
    {
        return atEnd;
    }

    private void readSpace()
    {
        String space;
        do
        {
            // Read empty space from the beginning
            space = read( SPACE );
        }
        while( ( null != space ) && !space.isEmpty() );
    }

    private String read( Pattern pattern )
    {
        begin = new FilePosition( lineNum, charNum );
        String line = getLine();
        if( null == line )
        {
            atEnd = true;
            return null;
        }
        Matcher m = pattern.matcher( line );
        if( m.find( charNum ) && ( charNum == m.start() ) )
        {
            charNum = m.end();
            end = new FilePosition( lineNum, charNum );
            return ( m.groupCount() > 0 ) ? m.group( 1 ) : m.group();
        }
        return null;
    }

    private String getLine()
    {
        if( ( null == line ) || ( charNum >= line.length() ) )
        {
            try
            {
                do
                {
                    line = reader.readLine();
                    lineNum++;
                }
                while( ( null != line ) && line.isEmpty() );
                charNum = 0;
            }
            catch( IOException e )
            {
                throw new RuntimeException( e );
            }
        }
        return line;
    }
}
